package language.monkey.parser

import language.monkey.ast.LetStatement
import language.monkey.ast.Program
import language.monkey.ast.Statement
import language.monkey.laxer.Lexer
import kotlin.test.Test
import kotlin.test.fail

class TestLetStatements {

    @Test
    fun testLetStatements() {

        val input = """
        let x = 5;
        let y = true;
        let foobar = 838383;
        """.trimIndent()

        val lexer = Lexer(input)

        val parser = Parser(lexer)
        val program: Program = parser.parseProgram()

        checkParserErrors(parser)

        if (program.statements.size != 3) {
            fail("program.statements does not contain 3 statements. got=%d".format(program.statements.size))
        }

        val tests = arrayOf(
            "x",
            "y",
            "foobar"
        )

        for ((index, pair) in tests.withIndex()) {
            val statement = program.statements[index]
            if (!testLetStatements(statement, pair)) {
                return
            }
        }
    }

    private fun checkParserErrors(program: Parser) {
        if (program.errors.isEmpty()) {
            return
        }
        error("Parser has %d errors\n%s".format(
            program.errors.size,
            program.errors.joinToString("\n")
        ))

    }

    fun testLetStatements(s: Statement, name: String): Boolean {

        if (s.tokenLiteral() != "let") {
            System.err.println("Expected let got ${s.tokenLiteral()}")
            return false
        }
        if (s !is LetStatement) {
            System.err.println("s not instance of LetStatement. got ${s.javaClass}")
            return false
        }

        if (s.name?.value != name) {
            System.err.println("Expected $name got ${s.name?.value}")
            return false
        }

        if (s.name?.tokenLiteral() != name) {
            System.err.println("letStmt.Name.TokenLiteral()  not $name got ${s.name?.tokenLiteral()}")
            return false
        }
        return true
    }
}